from hashlib import sha256
from pathlib import Path
from typing import List
from uuid import UUID

from fastapi import UploadFile
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession

from crud.bid_document_crud import BidDocumentCRUD
from crud.tender_crud import TenderCRUD
from .file_manager import FileManager


class BidInfo(BaseModel):
    name: str
    file_name: str
    file_path: str


class BidFileInfo(BaseModel):
    id: str
    name: str
    bargaining: bool


class BidService:
    def __init__(self, db: AsyncSession):
        self.tender_crud = TenderCRUD(db)
        self.bid_document_crud = BidDocumentCRUD(db)

    async def create_bids(
        self, tender_id: UUID, document: List[UploadFile]
    ) -> List[UUID]:
        tender = await self.tender_crud.get_by_id(tender_id)
        manager = FileManager(tender.category, tender.quarter)
        bid_document_ids: List[UUID] = []
        for doc in document:
            file_path = await manager.create_bid_document_file(doc)
            original_filename = Path(doc.filename).stem
            file_hash = sha256(await doc.read()).hexdigest()

            bid_document = await self.bid_document_crud.create(
                name=original_filename,
                file_path=str(file_path),
                tendering_id=tender.id,
                file_hash=file_hash,
                bargaining=False,
            )
            bid_document_ids.append(bid_document.id)
        return bid_document_ids

    async def get_info_by_tender_id(self, tender_id: UUID) -> List[BidFileInfo]:
        bid_documents = await self.bid_document_crud.get_by_tender_id(tender_id)
        return [
            BidFileInfo(
                id=str(doc.id),
                name=doc.name,
                bargaining=doc.bargaining,
            )
            for doc in bid_documents
        ]

    async def get_document_by_id(self, document_id: UUID) -> BidInfo:
        bid_document = await self.bid_document_crud.get_by_id(document_id)
        if not bid_document:
            raise ValueError("Document not found")
        return BidInfo(
            name=bid_document.name,
            file_name=Path(bid_document.file_path).name,
            file_path=bid_document.file_path,
        )

    async def update_bargaining(
        self, bid_document_id: UUID, bargaining_file: UploadFile
    ) -> None:
        bid_document = await self.bid_document_crud.get_by_id(bid_document_id)
        if not bid_document:
            raise ValueError("Bid document not found")
        tender = await self.tender_crud.get_by_id(bid_document.tendering_id)
        manager = FileManager(tender.category, tender.quarter)
        file_path = await manager.create_bid_bargaining_file(
            file=bargaining_file, bid_name=bid_document.name
        )
        bid_document = await self.bid_document_crud.update(
            doc_id=bid_document_id, bargaining=True
        )
        return

    async def delete_bid(self, bid_document_id: UUID):
        bid_document = await self.bid_document_crud.get_by_id(bid_document_id)
        if not bid_document:
            raise ValueError("Bid document not found")
        tender = await self.tender_crud.get_by_id(bid_document.tendering_id)
        manager = FileManager(tender.category, tender.quarter)
        await manager.delete_bid_document(bid_document.name)
        if bid_document.bargaining:
            await manager.delete_bid_bargaining_file(bid_document.name)
        await self.bid_document_crud.delete(bid_document_id)

    async def get_bargaining_by_id(self, bid_id):
        bid_document = await self.bid_document_crud.get_by_id(bid_id)
        if not bid_document or not bid_document.bargaining:
            raise ValueError("Bargaining file not found")
        file_name = f"{bid_document.name}_二次议价{Path(bid_document.file_path).suffix}"
        suffix = ".bargaining" + Path(bid_document.file_path).suffix
        file_path = Path(bid_document.file_path).with_suffix(suffix)
        return BidInfo(
            name=bid_document.name, file_name=file_name, file_path=str(file_path)
        )

    async def delete_bargaining(self, bid_id):
        bid_document = await self.bid_document_crud.get_by_id(bid_id)
        if not bid_document or not bid_document.bargaining:
            raise ValueError("Bargaining file not found")
        tender = await self.tender_crud.get_by_id(bid_document.tendering_id)
        manager = FileManager(tender.category, tender.quarter)
        await manager.delete_bid_bargaining_file(bid_document.name)
        await self.bid_document_crud.update(doc_id=bid_id, bargaining=False)
        return True
